# !/usr/bin/env python
# encoding: utf-8


"""
  @author: gaogao
  @file: check_equip_comm_thread.py
  @time: 2022/7/31 17:04
  @desc:
"""
from PyQt5.QtCore import QObject, pyqtSignal, QThread
import time
from utils.log_util import loggings
from ATS.switchdriver.LightSwitchDriver import LightSwitchDriver
from utils.read_ini_2_dict import get_option_value, get_refrence_data, get_loss_data, get_pd_loss_sys
from utils.get_wave_power_util import get_wave_power_value, get_wave_loss_gc
from ATS.util.calcu_step_util import get_points_list, get_step_list, get_step_array
from utils.find3db_util import find3db_util
from collections import namedtuple
from ATS.proberdriver.cascade_prober import CascadeProber
from ATS.application.LCR_App.U2722A_App import U2722A_App
from ATS.application.LCR_App.B2901BL_App import B2901BLApp
from ATS.application.LASER_App.L8164B_App import L8164B_App
from ATS.application.LASER_App.N7744C_App import N7744C_App
from utils.polynomial_fit_util import normalized, polynomial_fit
import datetime
from gui.driver.var_manager import VarManager
from utils.save_data_2_file import save_data_2_file_exper, save_spot_data_2_file


class VpiStabilityTask(QObject):
    result_signal = pyqtSignal(object, object)
    finished_signal = pyqtSignal()
    error_signal = pyqtSignal(object)

    def __init__(self, setting_info):
        super().__init__()
        self.duration = int(duration) * 60
        self.interval = int(interval)
        self.cp = CascadeProber()
        self.n7786_inst = N7786C_App("SS1")
        self.flag = True
        self.setting_info = setting_info

    def run(self):
        try:
            self.chuck_oprtical_probe_contact()
            self.probe_area_scan()
            self.steady_bias()
            time_stamp = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
            delay_time = 2
            vpi = self.setting_info.vpi
            start, stop, step = float(vpi["start"]), float(vpi["stop"]), float(vpi["step"])
            test_num = vpi["test_num"]
            interval = vpi["interval"]
            zero = vpi["zero"]
            voltage_vpp_list = get_step_array(start, stop, stop)
            result_data = namedtuple("result_data",
                                     "file_name,curve_type,y_invert,title,x_label,y_label,test_result")
            total_time = 10
            inst_light = LightSwitchDriver.instance()
            if inst_light.is_connected:
                inst_light.set_all_switch("01", "05")
                time.sleep(1)
                loggings.info("switch" + str(inst_light.query_switch()))
            else:
                inst_light.connect()
            l8164 = self.setting_info.l8164_setting
            n7744 = self.setting_info.n7744_setting
            l8164b_app = L8164B_App(l8164["title"])
            n7744c_app = N7744C_App(n7744["title"])

            l8164b_app.set_power_unit()
            l8164b_app.set_power_value(float(l8164["power_value"]))
            wave_length = l8164["wave_length"][0]
            l8164b_app.set_wave_length(int(wave_length))
            time.sleep(4)
            p_in = l8164b_app.fetch_input_power()
            l8164b_app.output_on()
            n7744c_app.reset()
            time.sleep(2)
            n7744c_app.set_power_wave_length()
            n7744c_app.set_power_unit()
            n7744c_app.set_power_range_auto()
            n7744c_app.set_power_atim(n7744["atim"])

            time.sleep(2)
            smu_setting = self.setting_info.smu_setting
            smu_dict = {}
            # smu voltage_list channel nplc current_range current_limit //mode sweep
            spci_meas_list = []
            mes_plans_dict = {"var_func": None, "var1": None, "measure_func": None}
            init_set_list = []
            b29smu_dict = {}
            init_b29_set_list = []
            b29_set_voltage_list = []
            b29_get_current_list = []
            b29_measure_list = []
            if smu_setting:
                for smu in smu_setting:
                    # if smu["smu"] == "SMU10":
                    if smu["smu"] == "SMU10" or smu["smu"] == "SMU11":
                        if smu["smu"] not in b29smu_dict:
                            b29smu_dict[smu["smu"]] = B2901BLApp(smu["smu"])
                        current_inst = b29smu_dict[smu["smu"]]
                        bias_voltage = smu["voltage_list"][0]
                        current_limit = smu["current_limit"]
                        init_b29_set_list += [lambda inst_obj=current_inst, voltage=bias_voltage,
                                                     current_limit=current_limit: inst_obj.spot_setting(
                            float(voltage), current_limit)]

                        b29_set_voltage_list += [
                            lambda x, inst_obj=current_inst, voltage=bias_voltage: inst_obj.set_voltage(
                                float(voltage) + float(x))]

                        b29_get_current_list += [lambda inst_obj=current_inst: inst_obj.get_current()]
                        b29_measure_list += [lambda inst_obj=current_inst: inst_obj.trigger_measure()]

                    else:
                        if smu["smu"] not in smu_dict:
                            smu_dict[smu["smu"]] = U2722A_App(smu["smu"])
                        current_inst = smu_dict[smu["smu"]]
                        current_voltage_list = smu["voltage_list"]
                        current_channel = smu["channel"]
                        current_channel_nplc = smu["nplc"]
                        current_channel_range = smu["current_range"]
                        current_channel_limit = smu["current_limit"]
                        init_set_list += [lambda y=current_channel,
                                                 inst_obj=current_inst: inst_obj.output_state(0, y),
                                          lambda x=current_channel, inst_obj=current_inst: inst_obj.set_voltage_range(
                                              x),
                                          lambda x=current_channel_nplc, y=current_channel,
                                                 inst_obj=current_inst: inst_obj.set_current_nplc(x, y),
                                          lambda x=current_channel_range, y=current_channel_limit,
                                                 z=current_channel,
                                                 inst_obj=current_inst: inst_obj.set_current_range_limit(x, y, z)]
                        if smu["mode"] == "sweep":
                            mes_plans_dict["var1"] = current_voltage_list
                            mes_plans_dict["var_func"] = lambda volt, x=current_channel, inst_obj=current_inst: \
                                inst_obj.set_voltage(volt, x)
                            mes_plans_dict["measure_func"] = lambda x=current_channel, inst_obj=current_inst: abs(
                                float(inst_obj.get_current_value(x)))
                        else:
                            init_set_list += [lambda x=current_voltage_list[0], y=current_channel,
                                                     inst_obj=current_inst: inst_obj.set_voltage(x, y)]

                            spci_meas_list += [lambda x, y=current_channel, z=current_voltage_list[0],
                                                      inst_obj=current_inst: inst_obj.set_voltage(
                                float(x) + float(z), y)]

                        if smu["is_measure"]:
                            mes_plans_dict["measure_func"] = lambda x=current_channel, inst_obj=current_inst: abs(
                                float(inst_obj.get_current_value(x)))

                        init_set_list += [lambda y=current_channel,
                                                 inst_obj=current_inst: inst_obj.output_state(1, y)]

                # set init
                for inst_set_func in init_set_list:
                    inst_set_func()  # 设置SMU
                for b29_set_func in init_b29_set_list:
                    b29_set_func()
                # read mes
                power_list = []
                mes_func = mes_plans_dict["measure_func"]
                if mes_func:  # mes func不为空
                    if mes_plans_dict["var1"]:  # sweep
                        for volt in mes_plans_dict["var1"]:
                            mes_plans_dict["var_func"](volt)
                            for b29_measre in b29_measure_list:
                                b29_measre()
                            time.sleep(0.1)
                            power_value = n7744c_app.get_power_value()
                            power_list.append(float(power_value))
                sweep_list = [float(i) for i in mes_plans_dict["var1"]]

                wave_power_tuple = get_refrence_data()
                loss_section = f"{VarManager().diex}-{VarManager().diey}-{VarManager().subdie_name.split('_')[0]}_GC"
                loss_gc = get_wave_loss_gc(l8164["wave_length"][0], get_loss_data(section=loss_section))
                loss_sys = get_wave_power_value(l8164["wave_length"][0], wave_power_tuple)
                title_section = f"{VarManager().diex}-{VarManager().diey}&{VarManager().subdie_name}&{bias_voltage}V_{wave_length}"
                title_path = f"{VarManager().save_folder}/{VarManager().wafer_name}"

                for num_index in range(len(power_list)):
                    power_list[num_index] = round(
                        (float(p_in) - power_list[num_index] - float(loss_sys) - 2 * float(loss_gc)), 3)

            datas = find3db_util(sweep_list, power_list)
            if datas and len(datas) == 4:
                # 设置bias电压
                if datas[0] != "" and datas[0] is not None:
                    half_slope_voltage = datas[0]
                    if mes_plans_dict["var1"]:
                        mes_plans_dict["var_func"](half_slope_voltage)
                    voltage_vpp_list = [float(i) for i in voltage_vpp_list]
                    save_spot_data_2_file(f"{title_path}.csv", f"{title_section}_Heater_3dB", str(half_slope_voltage))
                    p1_list, b2901_current_list, b2902_current_list = self.v_pi_test3(b29_set_voltage_list,
                                                                                      bias_voltage,
                                                                                      delay_time, n7744c_app,
                                                                                      total_time,
                                                                                      voltage_vpp_list,
                                                                                      b29_get_current_list)

                    time.sleep(6)
                    p2_list, b2901_current_list, b2902_current_list = self.v_pi_test4(b29_set_voltage_list,
                                                                                      bias_voltage,
                                                                                      delay_time, n7744c_app,
                                                                                      total_time,
                                                                                      voltage_vpp_list,
                                                                                      b29_get_current_list)

                    time.sleep(2)

                    save_spot_data_2_file(f"{title_path}.csv", f"{title_section}_IL", str(datas[3]))

                    p0 = float(datas[3]) - float(datas[1])

                    save_spot_data_2_file(f"{title_path}.csv", f"{title_section}_Power_3dB",
                                          str(p0))

                    p11_list = normalized(p0, p1_list)
                    p22_list = normalized(p0, p2_list)

                    p11_result = self.just_flag(p11_list)

                    p11_file_name = f"{title_section}_power_left_arm_{p11_result}_{time_stamp}"

                    curve_title = f"{title_section}_power_left_arm_{p11_result}_{time_stamp}"
                    x_label = "Voltage"
                    y_label = "Power"
                    post_array_data(curve_title, p11_list, result_data, p11_file_name, voltage_vpp_list, x_label,
                                    y_label)

                    time.sleep(2)
                    p22_result = self.just_flag(p22_list)
                    p11_file_name = f"{title_section}_power_right_arm_{p22_result}_{time_stamp}"

                    curve_title = f"{title_section}_power_right_arm_{p22_result}_{time_stamp}"
                    x_label = "Voltage"
                    y_label = "Power"

                    self.post_array_data(curve_title, p22_list, result_data, p11_file_name, voltage_vpp_list, x_label,
                                    y_label)

                    measurement_parameter = f"{para.subdie}&{bias_voltage}V_{wave_length}_power_right_arm_{p22_result}"
                    measurement_data = str([voltage_vpp_list, p22_list])
                    data_unit = ""
                    data_type = "Curve"
                    insert_chip(chip_name, wafer_name, shot_position, shot_number, chip_number, polarization_type,
                                measurement_parameter, measurement_data, data_unit, data_type)

                    voltage_vpp_list = [float(i) for i in voltage_vpp_list]

                    v_pi2, z2 = polynomial_fit(voltage_vpp_list, p22_list)
                    v_pi1, z1 = polynomial_fit(voltage_vpp_list, p11_list)

                    save_spot_data_2_file(f"{title_path}.csv", f"{title_section}_left_arm_{p11_result}",
                                          str(v_pi1))

                    save_spot_data_2_file(f"{title_path}.csv", f"{title_section}_right_arm_{p22_result}",
                                          str(v_pi2))

            QThread.sleep(2)
            self.finished_signal.emit()
        except Exception as e:
            self.error_signal.emit(str(e))
            loggings.error("VerifyStabilityTask" + str(e))
        finally:
            self.chuck_oprtical_probe_separation()

    def get_power_merter_value(self):
        return float(self.n7744_inst.get_power_value())

    def steady_bias(self):
        self.n7744_inst.set_logging_state("STOP")
        self.n7744_inst.reset()
        self.l8164_inst.set_wave_length(1310)
        self.l8164_inst.set_power_unit()
        self.l8164_inst.set_power_value(10)
        time.sleep(2)
        self.l8164_inst.output_on()

        self.n7744_inst.set_power_range(10)
        self.n7744_inst.set_auto_gain()
        self.n7744_inst.trigger_input_mode()
        self.n7744_inst.set_power_wave_length(1310)
        self.n7744_inst.set_logging_points()

        # init
        self.n7786_inst.reset()
        time.sleep(1)
        self.n7786_inst.set_stabilization_mode(0)
        self.n7786_inst.set_random_points_stepwidth()
        self.n7786_inst.set_trigger_conf_mode(4)
        self.n7786_inst.set_sample_point_rate()

        self.n7786_inst.set_wave_length(1310)
        self.n7786_inst.start_polarimeter_logging()
        self.n7786_inst.start_polarization_sequence()
        self.n7744_inst.set_logging_state("START")
        time.sleep(4)
        self.n7786_inst.trigger()
        while True:
            state = self.n7744_inst.get_func_state()
            if state == "LOGGING_STABILITY,COMPLETE":
                result_list = self.n7744_inst.get_func_res()
                break
        max_index = result_list.index(max(result_list))
        min_index = result_list.index(min(result_list))
        while True:
            log_value = self.n7786_inst.get_logged_value()
            if log_value == "+0":
                polarization_data = self.n7786_inst.get_polarization_sweep_data()
                break
        self.n7786_inst.stop_logging_polcontroller()
        state = self.n7786_inst.get_opc_state()
        if state == "1":
            self.n7786_inst.set_external_trigger_delay()
            self.n7786_inst.set_trigger_conf_mode()
            self.n7786_inst.set_stabilization_mode(1)

        max_polar = [polarization_data[max_index * 3], polarization_data[max_index * 3 + 1],
                     polarization_data[max_index * 3 + 2]]
        self.n7786_inst.set_polarization_value(*max_polar)
        self.n7744_inst.set_logging_state("STOP")

    def probe_area_scan(self):
        self.cp.area_scan()

    def chuck_oprtical_probe_contact(self):
        self.cp.move_chuck_contact()
        self.cp.move_optical_probe_height("H1")
        QThread.sleep(1)
        self.cp.move_optical_probe_height("H2")

    def chuck_oprtical_probe_separation(self):
        self.cp.move_chuck_separation()
        self.cp.move_optical_separation_height("H1")
        QThread.sleep(1)
        self.cp.move_optical_separation_height("H2")

    def v_pi_test3(self, b29_set_voltage_list, bias_voltage, delay_time, n7744c_app, total_time, voltage_vpp_list,
                   b29_get_current_list):
        p_total_list = []
        b2901_current = []
        b2902_current = []
        for voltage in voltage_vpp_list:
            b29_set_voltage_list[0](float(voltage))
            b29_set_voltage_list[1](0)
            for b29_measre in b29_measure_list:
                b29_measre()
            time.sleep(0.05)
            b2901_current.append(float(b29_get_current_list[0]()))
            b2902_current.append(float(b29_get_current_list[1]()))
            p_list = []
            for _ in range(total_time):
                p = n7744c_app.get_power_value()
                p_list.append(float(p))
                time.sleep(0.05)
            min_p = min(p_list)
            max_p = max(p_list)
            p_list.remove(min_p)
            p_list.remove(max_p)
            p = sum(p_list) / len(p_list)
            p_total_list.append(p)
            b29_set_voltage_list[0](-float(bias_voltage))
            b29_set_voltage_list[1](-float(bias_voltage))
            time.sleep(delay_time)
        return p_total_list, b2902_current, b2901_current

    def v_pi_test4(self, b29_set_voltage_list, bias_voltage, delay_time, n7744c_app, total_time, voltage_vpp_list,
                   b29_get_current_list):
        p_total_list = []
        b2901_current = []
        b2902_current = []
        for voltage in voltage_vpp_list:
            b29_set_voltage_list[1](float(voltage))
            b29_set_voltage_list[0](0)
            for b29_measre in b29_measure_list:
                b29_measre()
            time.sleep(0.05)
            b2901_current.append(float(b29_get_current_list[0]()))
            b2902_current.append(float(b29_get_current_list[1]()))
            p_list = []
            for _ in range(total_time):
                p = n7744c_app.get_power_value()
                p_list.append(float(p))
                time.sleep(0.05)
            min_p = min(p_list)
            max_p = max(p_list)
            p_list.remove(min_p)
            p_list.remove(max_p)
            p = sum(p_list) / len(p_list)
            p_total_list.append(p)
            b29_set_voltage_list[1](-float(bias_voltage))
            b29_set_voltage_list[0](-float(bias_voltage))
            time.sleep(delay_time)
        return p_total_list, b2901_current, b2902_current

    def just_flag(self, vp_list):
        if float(vp_list[-1]) > float(vp_list[0]):
            flag = "up"
        else:
            flag = "down"
        return flag

    def post_array_data(self, curve_title, p22_list, result_data, title_section, voltage_vpp_list, x_label, y_label):
        DataTransferStation.get_DTS().postarraydata("test",
                                                    result_data(title_section, 'line', False,
                                                                curve_title, x_label, y_label,
                                                                (voltage_vpp_list, p22_list)))
